import instance from "@/main";
import initSocket from "@/util/socket";
import globalSite from "@/config/globalSite";
import {
  toTree,
  checkOrderDetail,
  checkLineOrderDetail,
  getMessageSwitchStatus
} from "@/util/common";
import { formatRouter } from "@/util/permission";
import router, { resetRouter } from "@/router";
import socketDict from "@/dict/socket";

const socket = {
  state: {
    loginWs: null,
    loginWsReadyState: null,
    lockReconnect: false, // 连接锁，避免重复连接
    timeoutSet: null, // 延时器
    timeout: 3000, // 超时重连间隔
    reconnectNum: 1, // 重连次数
    heartbeatInterval: null,
    message: null, // 接收到的消息
    changeCompany: false // 是否切换公司
  },
  mutations: {
    // 更新消息
    UPDATE_MSG: (state, data) => {
      state.message = data;
    },
    RESET_RECONNECT_NUM: state => {
      state.reconnectNum = 1;
    },
    CLOSE_LOGIN_WS: state => {
      if (state.loginWs) state.loginWs.close();
      state = {
        loginWs: null,
        loginWsReadyState: null,
        lockReconnect: false, // 连接锁，避免重复连接
        timeoutSet: null, // 延时器
        timeout: 3000, // 超时重连间隔
        reconnectNum: 1, // 重连次数
        heartbeatInterval: null,
        message: null, // 接收到的消息
        changeCompany: false // 是否切换公司
      };
      clearInterval(state.heartbeatInterval);
    },
    // 切换公司
    SET_CHANGE_COMPANY: (state, data) => {
      return new Promise(resolve => {
        state.changeCompany = data;
        resolve();
      });
    }
  },
  actions: {
    // 是否在切换公司
    setChangeCompany: ({ commit }, data) => {
      return new Promise(resolve => {
        commit("SET_CHANGE_COMPANY", data);
        resolve();
      });
    },
    // 心跳
    heartbeat: ({ state }) => {
      state.heartbeatInterval = setInterval(() => {
        state.loginWs.send("heartbeat");
      }, 30000);
    },
    // 重置重连次数
    resetReconnectNum: ({ commit }) => {
      commit("RESET_RECONNECT_NUM");
    },
    // 重新连接
    reconnect: ({ state, dispatch }) => {
      if (state.lockReconnect) return;
      // 在登录注册页不进行重连
      if (
        instance.$route.name === "login" ||
        instance.$route.name === "register"
      ) {
        state.loginWsReadyState = null;
        state.lockReconnect = false;
        dispatch("resetReconnectNum");
        return;
      }
      console.log("ws准备重连");
      state.lockReconnect = true;
      // 重连最大次数3次
      if (state.reconnectNum <= 3) {
        state.loginWsReadyState = 0;
        state.timeoutSet = setTimeout(() => {
          console.log(`ws正在重连，第${state.reconnectNum}次`);
          dispatch("createLoginWs");
          state.reconnectNum++;
          state.lockReconnect = false;
        }, state.timeout); // 延迟3秒重连
      } else {
        console.log(`重连次数已超3次`);
        state.loginWsReadyState = null;
        state.lockReconnect = false;
        dispatch("resetReconnectNum");
        // 重连超过3次后退出登录
        dispatch("logout").then(() => {
          instance.$router.push({
            name: "home"
          });
        });
      }
    },
    // 创建登录socket
    createLoginWs: ({ state, commit, dispatch, rootState }) => {
      return new Promise(resolve => {
        state.loginWs = new initSocket(
          `ws/connect?${globalSite.accessToken}=${
            rootState.user.accessToken
          }&&${[globalSite.authToken]}=${
            rootState.user.authToken
          }&&terminalFlag=PCCHROME`
        );
        console.log(state.loginWs);
        state.loginWsReadyState = 0;
        // state.loginWs.onopen().then(() => {
        state.loginWs.onopen = () => {
          console.log("loginWs.onopen");
          // 开启心跳
          dispatch("heartbeat");
          state.loginWsReadyState = 1;
          dispatch("setIsLogin", true);
          // state.loginWs.onerror().then(err => {
          state.loginWs.onerror = err => {
            console.log("loginWs.onerror", err);
            // // 异常关闭时进行重连
            // dispatch("reconnect")
            // state.loginWsReadyState = null
          };
        };
        // });
        // state.loginWs.onmessage().then(data => {
        state.loginWs.onmessage = res => {
          let data = JSON.parse(res.data);
          // 更新消息
          commit("UPDATE_MSG", data);
          console.log("onmessage", data);
          let c = data.code;
          let d = data.data;
          // 处理路由信息，生成路由
          if (c === socketDict.code.router) {
            if (d) {
              commit("SET_INIT", true);
              // 剔除按钮
              let menus = d.filter(i => i.type === 0 || i.type === 2);
              let btns = d.filter(i => i.type === 1);
              dispatch("setButton", btns);
              dispatch("setAsyncRouter", menus);
              let routers = toTree(menus, 0, {
                id: "id",
                parentId: "webParentId"
              }); // 先将后端返回的动态路由数据转树，如果后端返回的数据已经是转树后的，则不需要这一步
              const asyncRouter = formatRouter(routers); // 将动态路由数据格式化，变成路由需要的格式
              localStorage.setItem("asyncRouter", JSON.stringify(asyncRouter));
              asyncRouter.push({
                path: "*",
                redirect: "/404"
              });
              dispatch("setRouter", asyncRouter);
              let rootAsyncRouter = [
                {
                  path: "/",
                  // name: "layout",
                  // 没有输入路径时，重定向到首页home
                  redirect: "/home",
                  component: () =>
                    import(
                      /* webpackChunkName: "layout" */
                      "@/page/basic-layout/index.vue"
                    ),
                  children: asyncRouter
                }
              ];
              console.log(rootAsyncRouter);
              router.addRoutes(rootAsyncRouter); // vue-router提供的addRouter方法进行路由拼接
              resolve(asyncRouter);
            } else {
              resolve(data);
            }
          }
          // 消息通知提示框
          // 路由、实名刷脸消息、下线 不显示提示框
          if (
            [
              socketDict.code.router,
              // socketDict.code.realnameFace,
              ...socketDict.code.offline
            ].indexOf(c) === -1
          ) {
            // 是否刷脸消息
            if (c === socketDict.code.realnameFace && d.messageType === 200)
              return;
            // 是否开启消息弹窗
            let messageSwitch = getMessageSwitchStatus();
            if (!messageSwitch) return;
            // 关闭最后一条消息时，清除所有消息提示框
            // destroy方法会把消息提示框容器也删除，所以无需手动删除全部清除按钮
            let destroyAll = () => {
              instance.$nextTick(() => {
                let notice = document.getElementsByClassName(
                  "ant-notification-topRight"
                );
                if (notice) {
                  if (
                    notice[0].getElementsByClassName("ant-notification-notice")
                      .length <= 1
                  ) {
                    // 关闭最后一条消息时，清除所有消息提示框
                    instance.$notification.destroy();
                  }
                }
              });
            };
            let key = d.id
              ? data.code + d.id + Date.parse(new Date())
              : undefined; // 唯一key，用于关闭消息（带有id时才设置key）
            instance.$notification.info({
              key: key,
              message: d.title,
              description: d.message,
              duration: null,
              onClick() {
                // 点击消息时关闭该消息
                if (key) instance.$notification.close(key);
                if (socketDict.code.quotation.indexOf(c) !== -1) {
                  // 点击报价消息跳转报价列表
                  instance.$router.push({ name: "quotationList" });
                } else if (socketDict.code.order.indexOf(c) !== -1) {
                  // 点击订单消息跳转订单详情
                  checkOrderDetail(d);
                } else if (socketDict.code.lineOrder.indexOf(c) !== -1) {
                  // 点击线路订单消息跳转线路订单详情
                  checkLineOrderDetail(d);
                }
                destroyAll();
              },
              onClose() {
                destroyAll();
              }
            });
            instance.$nextTick(() => {
              let destroyBtn = document.getElementsByClassName(
                "notice-destroy-btn"
              )[0];
              // 已存在清除所有消息按钮时，不需重新生成按钮
              if (destroyBtn) return;
              let button = document.createElement("button");
              let text = document.createElement("span");
              let icon = document.createElement("i");
              text.textContent = "全部清除";
              icon.textContent = "X";
              icon.className = "fs-16";
              icon.style.marginLeft = "3px";
              button.appendChild(icon);
              button.appendChild(text);
              button.className = "notice-destroy-btn fs-14 cursor-pointer";
              button.onclick = () => {
                // 清除所有消息提示框
                instance.$notification.destroy();
              };
              // 将清除按钮插入消息提示框列表
              let notice = document.getElementsByClassName(
                "ant-notification-topRight"
              )[0];
              notice.getElementsByTagName("span")[0].appendChild(button);
            });
          }
        };
        // });
        // state.loginWs.onclose().then(data => {
        state.loginWs.onclose = data => {
          state.loginWsReadyState = null;
          // 重置路由，避免添加重复路由
          resetRouter();
          console.log("loginWs.onclose", data);
          // 清除定时器
          clearInterval(state.heartbeatInterval);
          state.heartbeatInterval = null;
          dispatch("setIsLogin", false);
          // 清除所有消息提示框
          instance.$notification.destroy();
          // 是否在切换公司
          if (!state.changeCompany) {
            if (
              data.code === 1000 ||
              socketDict.code.offline.indexOf(data.code) !== -1
            ) {
              // code 4001 代表被踢下线; 1000 代表主动关闭；4003 代表同设备登录(authToken相同)
              dispatch("logout", data.code === 4003 ? 4003 : undefined);
              // state.loginWsReadyState = null;
              // 退登并返回首页
              instance.$router.push({
                name: "home"
              });
              // 踢下线弹窗提示
              if (data.code === 4001) {
                let now = new Date();
                let time = now.toLocaleTimeString("chinese", {
                  hour12: false
                });
                instance.$confirm({
                  title: "下线通知",
                  content: `你的账号于 ${time} 在另一设备登录了商城。如非本人操作，则密码可能已泄露，建议修改密码。`,
                  okText: "重新登录",
                  cancelText: "关闭",
                  icon: "exclamation-circle",
                  onOk() {
                    instance.$router.push({
                      name: "login"
                    });
                  }
                });
              }
              if (data.code === 4003) {
                instance.$storage.s_set("disableLogin", true); // 标记当前标签页禁止登录
                let now = new Date();
                let time = now.toLocaleTimeString("chinese", {
                  hour12: false
                });
                instance.$warning({
                  title: "下线通知",
                  content: `你的账号于 ${time} 在相同设备上登录了商城`
                });
              }
            } else {
              // 重置路由，避免添加重复路由
              // resetRouter();
              // dispatch("resetRouter");
              // 异常关闭时进行重连
              dispatch("reconnect");
            }
          }
        };
        // });
      });
    },
    // 关闭登录ws
    closeLoginWs: ({ commit }) => {
      commit("CLOSE_LOGIN_WS");
    }
  }
};

export default socket;
